#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include "LockGuard.hpp"
using namespace std;
const int defaultcapacity = 10;
template <class T>
class blockqueue {
    public :
    // 构造函数
    blockqueue(int capacity = defaultcapacity)
        :_capacity(capacity)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);

    }
    // 入队
    void Push(const T& val) {
        // 加锁
        LockGuard Lock(&_mutex);
        // pthread_mutex_lock(&_mutex);
        while (isFull()) { // 使用while是为了防止“伪唤醒"
            // 进行阻塞等待
            pthread_cond_wait(&_p_cond, &_mutex);
        }
        _q.push(val);
        // 唤醒消费者
        pthread_cond_signal(&_c_cond);
        // 解锁
        // pthread_mutex_unlock(&_mutex);


    }

    bool isFull() {
        return _q.size() == _capacity;
    }

    bool Empty() {
        return _q.empty();
    }

    // 出队
    void Pop(T *out) {
        // 因为生产和消费本身就是互斥的，所以他们两个必须申请同一把锁
        LockGuard Lock(&_mutex);
        // pthread_mutex_lock(&_mutex);
        while (Empty()) {
            // 也阻塞等待
            pthread_cond_wait(&_c_cond, &_mutex);
        }
        *out = _q.front();
        _q.pop();
        // 唤醒生产者
        pthread_cond_signal(&_p_cond);
        // pthread_mutex_unlock(&_mutex);

    }



    // 析构函数
   ~blockqueue() {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }
    private :
    queue<T> _q;
    int _capacity;
    pthread_mutex_t _mutex; // 保护队列的一把锁
    pthread_cond_t _c_cond; // 给消费者的条件变量
    pthread_cond_t _p_cond; // 给生产者的条件变量

};

